package cdu.sl.aichatdemo.filters;

import cdu.sl.aichatdemo.constants.JwtConstants;
import cdu.sl.aichatdemo.constants.SecurityConfigConstants;
import cdu.sl.aichatdemo.service.CustomUserService;
import cdu.sl.aichatdemo.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

/**
 * Jwt过滤器
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class JwtTokenFilter extends OncePerRequestFilter {

    private final JwtUtil jwtUtil;

    private final CustomUserService customUserService;

    @Value("${security.permit-urls}")
    private String permitUrlsStr;



    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String authHeader = request.getHeader(JwtConstants.AUTHORIZATION_HEADER);
        if(checkIsPermitRequest(request)){
            // 是否是被允许放行的路径
            log.info("放行路径:{}",request.getRequestURI());
            filterChain.doFilter(request,response);
            return;
        }
        // 从认证头中获取token
        String tokenFromAuthHeader = getTokenFromAuthHeader(authHeader);
        // 从token解析出用户信息并保存到SecurityContext
        savaInfoToSecurityContextFromToken(tokenFromAuthHeader);
        filterChain.doFilter(request,response);
    }


    /**
     * 从token解析用户信息并保存到SecurityContext
     * @param token 用户令牌
     */
    private void savaInfoToSecurityContextFromToken(String token) {
        if (jwtUtil.validateToken(token)) {
            // token合法 解析出声明 并将信息保存到SecurityContext上下文
            Long userId = jwtUtil.getUserIdFromToken(token);
            if (userId == null) {
                log.warn("Token: {}没有Id凭据", token);
            }
            Claims claims = jwtUtil.getClaimsFromToken(token);
            String email = (String) claims.get(JwtConstants.JWT_CLAIMS_EMAIL);
            UserDetails userDetails = customUserService.loadUserByUsername(email);
            // 创建已认证的用户信息
            Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
            // 将认证信息保存到上下文
            SecurityContextHolder.getContext().setAuthentication(authentication);
            log.info("token认证通过,放行请求...");
            log.info("已将认证信息信息：{}保存到Security上下文",userDetails.getUsername());
        } else {
            log.warn("Token校验不通过...: {}", token);
        }

    }


    /**
     * 检查请求路径是否应该被放行
     *
     * @param request Http请求
     * @return 是否放行
     */
    private boolean checkIsPermitRequest(HttpServletRequest request) {
        String uri = request.getRequestURI();
        String[] permitUrls = permitUrlsStr.split(SecurityConfigConstants.PERMIT_URL_DELIMITER);
        for (String permitUrl : permitUrls) {
            if (uri.contains(permitUrl)) {
                log.info("放行:{}", permitUrl);
                return true;
            }
        }
        return false;
    }


    private boolean checkIsJwtToken(String authHeader) {
        // 判断是不是Authorization认证头 ' Bearer开头'
        return authHeader != null && authHeader.startsWith(JwtConstants.JWT_AUTH_HEADER_PREFIX);
    }


    public String getTokenFromAuthHeader(String authHeader) {
        if (checkIsJwtToken(authHeader)) {
            return authHeader.substring(JwtConstants.JWT_AUTH_HEADER_PREFIX.length());
        }
        return null;
    }


}
